/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.commonmodel.core.session.sessioncache;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.cef.api.session.ICefSessionItem;
import com.inspur.edp.commonmodel.core.session.distributed.dac.FuncSessionIncrement;
import com.inspur.edp.commonmodel.core.session.json.SessionIncrementDeserializer;
import com.inspur.edp.commonmodel.core.session.json.SessionIncrementSerializer;
import com.inspur.edp.commonmodel.core.session.serviceinterface.SessionCacheInfoService;
import com.inspur.edp.commonmodel.core.session.tableentity.SessionCacheInfo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import javax.transaction.Transactional;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.springframework.util.StringUtils;

public class SessionCacheInfoServiceImpl implements SessionCacheInfoService {

    private final SessionCacheInfoRepository repository;

    public SessionCacheInfoServiceImpl(SessionCacheInfoRepository repository){
        this.repository = repository;
    }

    @Override
    public List<SessionCacheInfo> getSessionCacheInfos(String sessionId, int version){
        List<SessionCacheInfo> infos = repository.getSessionCacheInfosBySessionIdAndVersionGreaterThanOrderByVersion(sessionId,version);
        for(SessionCacheInfo info : infos){
            if(StringUtils.isEmpty(info.getSessionContent()))
                continue;
            info.setSessionChangeSet(DeSerializeChangeSet(info.getSessionContent()));
        }
        return infos;
    }

    @Override
    public void saveSessionCacheInfo(SessionCacheInfo info, Map<String, ICefSessionItem> items){
        if(info.getSessionChangeSet() != null) {
            info.setSessionContent(SerializeChangeSet(info.getSessionChangeSet(), items));
        }
        repository.save(info);
    }

    @Override
    @Transactional
    public void deleteSessionCacheInfos(String id,int version){
        repository.deleteSessionCachesInfoBySessionIdAndVersionLessThanEqual(id,version);
    }

    @Override
    @Transactional
    public void clearSessionCacheInfos(String sessionId){
        repository.deleteAllBySessionId(sessionId);
    }

    @Override
    public List<SessionCacheInfo> traversalSessionCacheInfos(Date date){
        return repository.findTop500ByCreatedOnAfterAndVersionEqualsOrderByCreatedOn(date,0);
    }

    @Override
    @Transactional
    public void batchClear(List<String> sessionIds){
        repository.deleteSessionCacheInfosBySessionIdIn(sessionIds);
    }

    private String SerializeChangeSet(FuncSessionIncrement increment,  Map<String, ICefSessionItem> items){
        ObjectMapper mapper = getMapper(items);
        try {
            String value = null;
            if(increment!=null) {
                value = mapper.writeValueAsString(increment);
            }
            return value;
        } catch (JsonProcessingException | RuntimeException e) {
            throw new RuntimeException("ChangeSet序列化失败",e);
        }
    }

    private FuncSessionIncrement DeSerializeChangeSet(String increment){
        ObjectMapper mapper = getMapper();
        try {
            FuncSessionIncrement vm = mapper.readValue(increment, FuncSessionIncrement.class);
            return vm;
        } catch (IOException e) {
            throw new RuntimeException("ChangeSet反序列化失败",e);
        }
    }

    private ObjectMapper getMapper(){
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(FuncSessionIncrement.class, new SessionIncrementDeserializer());
        mapper.registerModule(module);
        return mapper;
    }

    private ObjectMapper getMapper( Map<String, ICefSessionItem> items){
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addSerializer(FuncSessionIncrement.class, new SessionIncrementSerializer(items));
        mapper.registerModule(module);
        return mapper;
    }

    @Override
    public boolean isLatestVersion(String id,int ver){
        return !(repository.existsSessionCacheInfoBySessionIdAndVersionGreaterThan(id,ver));
    }
}
